// 有三种状态，状态流向为：
// pending => fullfilled
// pending => rjected
const PENDING = 'pending'
const FULLFILLED = 'fullfilled'
const REJECTED = 'rejected'
const isFn = (fn) => typeof fn === 'function'

class MyPromise {
	// promise 实例化的时候立即执行 excutor 函数, 并传入 resolve 和 reject 函数，在对应的时机执行
	constructor(executor) {
		executor(this.resolve, this.reject)
	}
	status = PENDING
	value = void 0
	reason = void 0
	successCallbacks = []
	failCallbacks = []
	resolve = (value) => {
		if (this.status !== PENDING) return
		this.status = FULLFILLED
		this.value = value
		this.successCallbacks.forEach((cb) => cb())
	}
	reject = (reaseon) => {
		if (this.status !== PENDING) return
		this.status = REJECTED
		this.reason = reaseon
		this.failCallbacks.forEach((cb) => cb())
	}
	// 在状态为 fullfiled 的时候执行 resolve，在 rejected 的时候执行 reject
	then(successCallback, failCallback) {
		// 如果传入的参数不是函数，则使用默认函数
		successCallback = isFn(successCallback) ? successCallback : (value) => value
		failCallback = isFn(failCallback) ? failCallback : (reason) => reason
		let p1 = new MyPromise((resolve, reject) => {
			if (this.status === FULLFILLED) {
				// 使用 settimeout 异步获取 p1 实例
				setTimeout(() => {
					try {
						const v = successCallback(this.value)
						// 处理上一个 then 返回的值
						resolvePromise(p1, v, resolve, reject)
					} catch (e) {
						reject(e)
					}
				}, 0)
			} else if (this.status === REJECTED) {
				setTimeout(() => {
					try {
						const v = failCallback(this.reason)
						// 处理上一个 then 返回的值
						resolvePromise(p1, v, resolve, reject)
					} catch (e) {
						reject(e)
					}
				}, 0)
			} else {
				// 在异步场景，需要在 pending 时候将异步回调收集起来
				this.successCallbacks.push(() => {
					setTimeout(() => {
						try {
							const v = successCallback(this.value)
							// 处理上一个 then 返回的值
							resolvePromise(p1, v, resolve, reject)
						} catch (e) {
							reject(e)
						}
					}, 0)
				})
				this.failCallbacks.push(() => {
					setTimeout(() => {
						try {
							const v = failCallback(this.reason)
							// 处理上一个 then 返回的值
							resolvePromise(p1, v, resolve, reject)
						} catch (e) {
							reject(e)
						}
					}, 0)
				})
			}
		})
		return p1
	}
	finally(callback) {
		return this.then(value=> {
			Promise.resolve(callback()).then(() => value)
		}, reason=>{
			Promise.resolve(callback()).then(() => { throw reason })
		})
	}
	catch(failCallback) {
		return this.then(null, failCallback)
	}
	static all(array = []) {
		const result = []
		let index = 0
		return new MyPromise((resolve) => {
			const addData = (i, v) => {
				result[i] = v
				index++
				if (index === array.length) {
					resolve(result)
				}
			}
			for (let i = 0; i < array.length; i++) {
				if (array[i] instanceof MyPromise) {
					array[i].then(
						(v) => {
							addData(i, v)
						},
						(reason) => reject(reason)
					)
				} else {
					addData(i, array[i])
				}
			}
		})
	}
	// 如果是 promise 直接返回，否则创建 promise 并 resolve
	static resolve(value) {
		if (value instanceof MyPromise) return value
		return new MyPromise((resolve) => {
			resolve(value)
		})
	}
}

// 处理 v 可能为 promise 的场景
function resolvePromise(p1, v, resolve, reject) {
	// 解决重复返回自己问题
	if (v === p1) {
		return reject(new Error('禁止重复使用自己'))
	}
	if (v instanceof MyPromise) {
		v.then(resolve, reject)
	} else {
		resolve(v)
	}
}

// ===========================================================================
// ===========================================================================
// ===========================================================================
// all test
// p3 = new MyPromise((resolve) => {
// 	setTimeout(() => {
// 		resolve(3)
// 	}, 2000)
// })
// MyPromise.all([ 1, 2, p3, 4 ]).then((result) => {
// 	console.log(result)
// })

// let promise = new MyPromise((resolve, reject) => {
// 	// resolve('成功')
// 	reject('失败')
// })

// promise.then(promise, promise).then(
// 	(value) => {
// 		console.log(value)
// 	},
// 	(reason) => {
// 		console.log(reason)
// 	}
// )
